package com.jfinal.core;

import java.io.File;
import java.lang.reflect.Field;
import java.util.Locale;

import javax.servlet.ServletContext;

import com.jfinal.config.Constants;
import com.jfinal.config.JFinalConfig;
import com.jfinal.handler.Handler;
import com.jfinal.handler.HandlerFactory;
import com.jfinal.kit.PathKit;
import com.jfinal.render.RenderFactory;
import com.jfinal.token.ITokenCache;
import com.jfinal.token.TokenManager;
import com.jfinal.upload.OreillyCos;
import com.jfinal.util.ReflectUtils;

public abstract class AbstractSpringJFinal extends AbstractSpring implements SpringJFinal {
	// jfinal Field
	private static final Field handler_Field = ReflectUtils.field(JFinal.class, "handler");
	private static final Field actionMapping_Field = ReflectUtils.field(JFinal.class, "actionMapping");
	private static final Field servletContext_Field = ReflectUtils.field(JFinal.class, "servletContext");
	private static final Field contextPath_Field = ReflectUtils.field(JFinal.class, "contextPath");
	private static final Field constants_Field = ReflectUtils.field(JFinal.class, "constants");

	private JFinal jfinal;

	private Constants constants;
	private ActionMapping actionMapping;
	private Handler handler;
	private ServletContext servletContext;

	public AbstractSpringJFinal(JFinal jfinal) {
		this.jfinal = jfinal;
	}

	@Override
	public boolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {
		this.setServletContext(servletContext);
		this.setContextPath(servletContext.getContextPath());

		initPathUtil();

		Config.configJFinal(jfinalConfig); // start plugin and init logger factory in this method

		this.setConstants(Config.getConstants());

		initActionMapping();
		initHandler();
		initRender();
		initOreillyCos();
		initI18n();
		initTokenManager();

		return true;
	}

	/*-------------------------------------------------*/
	public void setActionMapping(ActionMapping actionMapping) {
		ReflectUtils.set(jfinal, actionMapping_Field, this.actionMapping = actionMapping);
	}

	public void setHandler(Handler handler) {
		ReflectUtils.set(jfinal, handler_Field, this.handler = handler);
	}

	public void setConstants(Constants constants) {
		ReflectUtils.set(jfinal, constants_Field, this.constants = constants);
	}

	public void setServletContext(ServletContext servletContext) {
		ReflectUtils.set(jfinal, servletContext_Field, this.servletContext = servletContext);
	}

	public void setContextPath(String contextPath) {
		ReflectUtils.set(jfinal, contextPath_Field, contextPath);
	}

	public Handler getHandler() {
		return handler;
	}

	/*-------------------------------------------------*/
	private void initTokenManager() {
		ITokenCache tokenCache = constants.getTokenCache();
		if (tokenCache != null) TokenManager.init(tokenCache);
	}

	private void initI18n() {
		try {
			String i18nResourceBaseName = ReflectUtils.invoke(constants, "getI18nResourceBaseName");
			if (i18nResourceBaseName != null) {
				Integer i18nMaxAgeOfCookie = ReflectUtils.invoke(constants, "getI18nMaxAgeOfCookie");
				Locale defaultLocale = ReflectUtils.invoke(constants, "getI18nDefaultLocale");
				ReflectUtils.invoke(null//
						, "init"//
						, ReflectUtils.forName("com.jfinal.i18n.I18N")//
						, "getI18nDefaultLocale"//
						, i18nResourceBaseName, defaultLocale, i18nMaxAgeOfCookie);
			}
		} catch (Exception e) {
			// ignoge Exception
			// JFinal 2.*
		}
	}

	private void initHandler() {
		Handler actionHandler = new SpringHandler(actionMapping, constants, super.getApplicationContext());
		handler = HandlerFactory.getHandler(Config.getHandlers().getHandlerList(), actionHandler);
		this.setHandler(handler);
	}

	private void initOreillyCos() {
		try {
			Constants ct = constants;
			boolean isMultipartSupported = ReflectUtils.invoke(null, "isMultipartSupported", OreillyCos.class);

			if (isMultipartSupported) {
				String uploadedFileSaveDirectory = ct.getUploadedFileSaveDirectory();
				if (uploadedFileSaveDirectory == null || "".equals(uploadedFileSaveDirectory.trim())) {
					uploadedFileSaveDirectory = PathKit.getWebRootPath() + File.separator + "upload" + File.separator;
					ct.setUploadedFileSaveDirectory(uploadedFileSaveDirectory);

					/*File file = new File(uploadedFileSaveDirectory);
					if (!file.exists())
						file.mkdirs();*/
				}
				OreillyCos.init(uploadedFileSaveDirectory, ct.getMaxPostSize(), ct.getEncoding());
			}
		} catch (Exception e) {
			// ignoge Exception
			// JFinal 2.*
			OreillyCos.init(constants.getUploadedFileSaveDirectory(), constants.getMaxPostSize(), constants.getEncoding());
		}
	}

	private void initPathUtil() {
		String path = servletContext.getRealPath("/");
		PathKit.setWebRootPath(path);
	}

	private void initRender() {
		RenderFactory renderFactory = RenderFactory.me();
		renderFactory.init(constants, servletContext);
	}

	private void initActionMapping() {
		actionMapping = new ActionMapping(Config.getRoutes(), Config.getInterceptors());
		actionMapping.buildActionMapping();
		this.setActionMapping(actionMapping);
	}
}
